package com.iflytek.cosmo.ocr.service.impl;

import com.github.tobato.fastdfs.service.AppendFileStorageClient;
import com.iflytek.cosmo.ocr.common.enums.ExportTaskStatusEnum;
import com.iflytek.cosmo.ocr.common.util.JSONUtil;
import com.iflytek.cosmo.ocr.dao.ExportTaskDao;
import com.iflytek.cosmo.ocr.model.entity.ExportTaskEntity;
import com.iflytek.cosmo.ocr.service.ExportTaskService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.entity.Example.Criteria;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author <a href=mailto:ktyi@iflytek.com>伊开堂</a>
 * @date 2019/12/3 16:38
 */
@Service
public class ExportTaskServiceImpl implements ExportTaskService {
    private static final Logger logger = LoggerFactory.getLogger(ExportTaskServiceImpl.class);

    @Autowired
    private ExportTaskDao exportTaskDao;

    @Resource(name = "deleteFileExecutor")
    private ThreadPoolTaskExecutor DELETE_FILE_THREAD_POOL;

    /**
     * storageClient
     */
    @Autowired
    private AppendFileStorageClient storageClient;


    @Override
    public boolean create(ExportTaskEntity newTask) {
         int i = exportTaskDao.insertSelective(newTask);
         if (i > 0){
             return true;
         }
        return false;
    }

    @Override
    public List<ExportTaskEntity> find(String fileIds, String exportFormat) {
        ExportTaskEntity exportTaskEntity = new ExportTaskEntity();
        exportTaskEntity.setFileIds(fileIds);
        exportTaskEntity.setExportType(exportFormat);
        List<ExportTaskEntity> exportTaskEntities = exportTaskDao.select(exportTaskEntity);
        return exportTaskEntities;
    }

    @Override
    public boolean update(String taskId, ExportTaskStatusEnum targetStatus, String filePath) {
        int i = 0;
        try {
            Date updateTime = new Date();
            ExportTaskEntity exportTaskEntity = new ExportTaskEntity();
            exportTaskEntity.setId(taskId);
            exportTaskEntity.setUpdateTime(updateTime);
            exportTaskEntity.setStatus(targetStatus.toString());
            exportTaskEntity.setFilePath(filePath);
            i = exportTaskDao.updateByPrimaryKeySelective(exportTaskEntity);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (i > 0){
            return true;
        }
        return false;
    }

    @Override
    public boolean deleteByTaskId(String taskId) {
    	//删除任务
    	Example example = new Example(ExportTaskEntity.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("id", taskId);
		ExportTaskEntity exportTaskEntity=exportTaskDao.selectOneByExample(example);
		//删除fastDFS
		String filePath=exportTaskEntity.getFilePath();
		deleteFastDFSFile(filePath);
		//删除表记录
		exportTaskDao.deleteByExample(example);
        return false;
    }

    private void fastdfsDeleteFile(List<ExportTaskEntity> fileList){
        final CountDownLatch countDownLatch = new CountDownLatch(fileList.size());
        fileList.forEach(fi->{
            DELETE_FILE_THREAD_POOL.execute(()->{
                try {
                    logger.info(">>>>>>>>>>>开始删除文件");
                    if (fi.getFilePath() != null) {
                        String path = fi.getFilePath();
                        String groupName = path.substring(0, path.indexOf("/"));
                        String attpath = path.substring(path.indexOf("/") + 1);
                        storageClient.deleteFile(groupName, attpath);
                    }
                }catch (Exception ex){
                    logger.info(">>>>>>>>>>>删除文件失败");
                }
            });
        });
    }

    @Override
    public List<ExportTaskEntity> findByFileId(String fileId) {
        if (StringUtils.isBlank(fileId)) {
            return null;
        }

        Example example = new Example(ExportTaskEntity.class);
        example.createCriteria().andLike("fileIds", "%" + fileId + "%");
        return exportTaskDao.selectByExample(example);
    }

    @Override
    public List<ExportTaskEntity> findByFileId(List<String> fileIds) {
        if (CollectionUtils.isEmpty(fileIds)) {
            return null;
        }

        Example example = new Example(ExportTaskEntity.class);
        Example.Criteria criteria = example.createCriteria();
        for (String fileId : fileIds) {
            criteria.orLike("fileIds", "%" + fileId + "%");
        }

        return exportTaskDao.selectByExample(example);
    }

    @Override
    public int cleanupByFileId(List<String> fileIds) {
        List<ExportTaskEntity> tasks = findByFileId(fileIds);
        return cleanup(tasks);
    }

    @Override
    public int cleanupByFileId(String fileId) {
        logger.info("清理包含文件: {} 的导出任务", fileId);
        if (StringUtils.isBlank(fileId)) {
            return 0;
        }

        List<ExportTaskEntity> tasks = findByFileId(fileId);
        return cleanup(tasks);
    }

    @Override
    public int cleanup(List<ExportTaskEntity> tasks) {
        if (CollectionUtils.isEmpty(tasks)) {
            return 0;
        }

        // 批量删除数据库数据
        List<String> taskIds = tasks.stream().map(ExportTaskEntity::getId).collect(Collectors.toList());
        logger.debug("待清理的过期文件导出任务id: {}", JSONUtil.toStrByDefault(taskIds));

        Example example = new Example(ExportTaskEntity.class);
        example.createCriteria().andIn("id", taskIds);
        int deletedSize = exportTaskDao.deleteByExample(example);
        logger.info("已从数据库删除过期任务数据{}条", deletedSize);

        // 循环删除 fastDFS 数据库
        tasks.forEach(t -> deleteFastDFSFile(t.getFilePath()));

        return deletedSize;
    }

    private void deleteFastDFSFile(String filePath) {
        try {
            logger.debug("开始删除文件: {}", filePath);
            if (StringUtils.isNotBlank(filePath)) {
                String groupName = filePath.substring(0, filePath.indexOf("/"));
                String attpath = filePath.substring(filePath.indexOf("/") + 1);
                storageClient.deleteFile(groupName, attpath);
            }
        }
        catch (Exception e) {
            logger.info("删除fastDFS文件异常, filePath: {}", filePath, e);
        }
    }

    @Override
    public List<ExportTaskEntity> findExpiredTask(int keepAliveTime, TimeUnit timeUnit) {
        long keepAliveSec = timeUnit.toSeconds(keepAliveTime);
        Date now = new Date();
        Date deadline = DateUtils.addSeconds(now, Math.toIntExact(-1 * keepAliveSec));

        Example example = new Example(ExportTaskEntity.class);
        example.createCriteria().andLessThan("createTime", deadline);
        return exportTaskDao.selectByExample(example);
    }

	@Override
	public void delete(List<String> taskIds) {
        Example example = new Example(String.class);
        example.createCriteria().andIn("id", taskIds);
        exportTaskDao.deleteByExample(example);
	}

    @Override
    public List<String> findOverTimeProcessingTask(int overTimeMinute) {
        Example example = new Example(ExportTaskEntity.class);
        example.createCriteria().andEqualTo("status", ExportTaskStatusEnum.PROCESSING.toString());
        List<ExportTaskEntity> exportTaskEntities = exportTaskDao.selectByExample(example);
        if (CollectionUtils.isEmpty(exportTaskEntities)){
            return null;
        }
        List<String> processingOverTimeTaskId = new ArrayList<>();
        //当前时间
        Date currentTime = new Date();
        for (ExportTaskEntity exportTaskEntity : exportTaskEntities){
            //创建时间
            Date createTime = exportTaskEntity.getCreateTime();
            Date compareTime = DateUtils.addMinutes(createTime, overTimeMinute);
            int compareResult = compareTime.compareTo(currentTime);
            if (compareResult < 0){
                processingOverTimeTaskId.add(exportTaskEntity.getId());
            }
        }
        return processingOverTimeTaskId;
    }

    @Override
    public void deleteOverTimeTask(List<String> overTimeTaskIdList) {
        if (CollectionUtils.isNotEmpty(overTimeTaskIdList)){
            Example example = new Example(ExportTaskEntity.class);
            example.createCriteria().andIn("id", overTimeTaskIdList);
            exportTaskDao.deleteByExample(example);
        }
    }

    @Override
    public List<ExportTaskEntity> findFinishTask(List<String> fileIds, String exportFormat, ExportTaskStatusEnum exportTaskStatusEnum) {
        Example example = new Example(ExportTaskEntity.class);
        example.createCriteria().andEqualTo("exportType", exportFormat).andEqualTo("status", exportTaskStatusEnum.toString()).andIn("fileIds", fileIds);
        List<ExportTaskEntity> exportTaskEntities = exportTaskDao.selectByExample(example);
        return exportTaskEntities;
    }
}
